package com.ruoyi.web.controller.gd;

import java.io.*;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.amazonaws.util.IOUtils;
import com.aspose.cells.SaveFormat;
import com.aspose.cells.Workbook;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.gd.fj.domain.bo.ZFujianBo;
import com.ruoyi.gd.fj.domain.vo.ZFujianVo;
import com.ruoyi.gd.wjglfl.domain.ZWjglFl;
import com.ruoyi.gd.ywdwgd.domain.vo.ZYwdwgdVo;
import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.core.validate.QueryGroup;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.gd.wjglfl.domain.vo.ZWjglFlVo;
import com.ruoyi.gd.wjglfl.domain.bo.ZWjglFlBo;
import com.ruoyi.gd.wjglfl.service.IZWjglFlService;
import org.springframework.web.multipart.MultipartFile;

import static com.ruoyi.web.controller.utils.LicenseData.getLicense;

/**
 * 文件管理分类
 *
 * @author ruoyi
 * @date 2024-10-27
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/gd/wjglfl")
public class ZWjglFlController extends BaseController {

    private final IZWjglFlService iZWjglFlService;

    @Value("${upload.wjgl}")
    private String uploadPath;

    /**
     * 查询文件管理分类列表
     */
    @GetMapping("/list")
    public R<List<Tree<String>>> list(ZWjglFlBo bo) {
        List<Tree<String>> list = iZWjglFlService.queryList(bo);
        return R.ok(list);
    }

    /**
     * 全局检索
     */
    @GetMapping("/global/list")
    public List<ZWjglFlVo> globalList(ZWjglFlBo bo) {
        List<ZWjglFlVo> list = iZWjglFlService.queryListExcel(bo);
        return list;
    }

    /**
     * 导出文件管理分类列表
     */
    @Log(title = "文件管理分类", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(ZWjglFlBo bo, HttpServletResponse response) {
        List<ZWjglFlVo> list = iZWjglFlService.queryListExcel(bo);
        ExcelUtil.exportExcel(list, "文件管理分类", ZWjglFlVo.class, response);
    }

    /**
     * 获取文件管理分类详细信息
     *
     * @param id 主键
     */
    @GetMapping("/{id}")
    public R<ZWjglFlVo> getInfo(@NotNull(message = "主键不能为空")
                                     @PathVariable String id) {
        return R.ok(iZWjglFlService.queryById(id));
    }

    /**
     * 新增文件管理分类
     */
    @Log(title = "文件管理分类", businessType = BusinessType.INSERT)
    @RepeatSubmit()
    @PostMapping()
    public R<Void> add(@Validated(AddGroup.class) @RequestBody ZWjglFlBo bo) {
        return toAjax(iZWjglFlService.insertByBo(bo));
    }

    /**
     * 修改文件管理分类
     */
    @Log(title = "文件管理分类", businessType = BusinessType.UPDATE)
    @RepeatSubmit()
    @PutMapping()
    public R<Void> edit(@Validated(EditGroup.class) @RequestBody ZWjglFlBo bo) {
        return toAjax(iZWjglFlService.updateByBo(bo));
    }

    /**
     * 删除文件管理分类
     *
     * @param ids 主键串
     */
    @Log(title = "文件管理分类", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public R<Void> remove(@PathVariable String ids) {
        String[] split = ids.split(",");
        return toAjax(iZWjglFlService.deleteWithValidByIds(Arrays.asList(split), true));
    }

    /**
     * 获取最大的排序
     * @param pid
     * @return
     */
    @GetMapping("/maxPx/{pid}")
    public R<Integer> queryMaxPx(@PathVariable("pid") String pid) {
        return R.ok(iZWjglFlService.queryMaxPx(pid));
    }

    /**
     * 文件上传
     * @param file
     * @param data
     * @return
     * @throws Exception
     */
    @PostMapping("/file/upload")
    public ResponseEntity<Object> upload(@RequestParam("file") MultipartFile file, @RequestParam("data") String data) throws Exception {
        if (file.isEmpty()) {
            return ResponseEntity.badRequest().body("File is empty.");
        }
        // 获取文件原名
        String originalFilename = file.getOriginalFilename();
        // 判断当前地址是否存在，不存在则创建
        Path filePath = Paths.get(uploadPath);
        // 判断路径是否存在
        if (!Files.exists(filePath)) {
            // 如果路径不存在，则尝试创建目录（假设uploadPath是指向目录的）
            Files.createDirectories(filePath);
        }
        // 获取后缀
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
        String fielName = originalFilename.substring(0,originalFilename.lastIndexOf("."));
        // 重新生成文件名
        LocalDate currentDate = LocalDate.now();
        // 分别获取年、月、日
        int year = currentDate.getYear();
        int monthValue = currentDate.getMonthValue();
        int dayOfMonth = currentDate.getDayOfMonth();
        // 生成Excel路径
        String suffixPath = "/" + year + "/" + monthValue + "/" + dayOfMonth + "/";
        // 判断当前文件路径的文件夹是否存在，不存在则创建
        if (!Files.exists(Paths.get(uploadPath + suffixPath))) {
            // 路径不存在，尝试创建
            try {
                Files.createDirectories(Paths.get(uploadPath + suffixPath));
            } catch (Exception e) {
                System.err.println("创建目录时出错: " + e.getMessage());
            }
        }
        // 构建新的文件名和目标路径
        Path targetLocation = Paths.get(uploadPath + suffixPath + originalFilename);
        // 将文件保存到指定目录
        Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);

        LoginUser loginUser = LoginHelper.getLoginUser();
        // 将当前的的数据进行新增到数据库
        JSONObject jsonObject = JSONUtil.parseObj(data);
        ZWjglFlBo zWjglFlBo = new ZWjglFlBo();
        zWjglFlBo.setId(IdUtil.simpleUUID()); // 设置id
        zWjglFlBo.setPid(jsonObject.getStr("id")); // 设置pid
        zWjglFlBo.setFilename(fielName);  // 设置文件名
        zWjglFlBo.setFilecode(generatePinyinInitials(originalFilename));  // 设置编码
        zWjglFlBo.setFiletype(suffix);  // 设置后缀
        zWjglFlBo.setCategory("1"); // 设置种类
        // 处理文件类型，设置图标
        String[] iconObj = handleFileIcon(suffix);
        zWjglFlBo.setIcon(iconObj[0]);  // 设置图标
        zWjglFlBo.setIconcolor(iconObj[1]);  // 设置图标
        // 处理当前的最大排序
        int px = getMaxPx(jsonObject.getJSONArray("children"));
        zWjglFlBo.setPx(px);  // 设置排序
        zWjglFlBo.setReadonly("false"); // 只读
        zWjglFlBo.setCreateId(loginUser.getUserId()+"");  // 设置创建人id
        zWjglFlBo.setFilepath(suffixPath + originalFilename);
        zWjglFlBo.setUpdateTime(new Date());
        zWjglFlBo.setUpdateBy(loginUser.getUsername());
        iZWjglFlService.insertByBo(zWjglFlBo);  // 新增数据
        return ResponseEntity.ok(true);
    }

    // 获取最大排序
    public int getMaxPx(JSONArray jsonArray) {
        // 初始化最大值和对应的 JSONObject
        int maxPx = 1;

        if(jsonArray != null) {
            // 遍历 JSONArray
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                int px = jsonObject.getInt("px");
                // 比较并更新最大值
                if (px > maxPx) {
                    maxPx = px;
                }
            }
        }

        return maxPx + 1;
    }

    // 生成字母
    public String generatePinyinInitials(String name) {
        String pinyin = "";
        HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
        format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
        format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);

        for (char c : name.toCharArray()) {
            if (Character.toString(c).matches("[\\u4E00-\\u9FA5]+")) {
                try {
                    String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(c, format);
                    if (pinyinArray != null && pinyinArray.length > 0) {
                        char initial = pinyinArray[0].charAt(0);
                        pinyin += initial;
                    }
                } catch (BadHanyuPinyinOutputFormatCombination e) {
                    e.printStackTrace();
                }
            } else {
                pinyin += c;
            }
        }
        return pinyin;
    }

    // 处理文件图标
    public String[] handleFileIcon(String suffix) {
        String[] strings = new String[2];
        switch (suffix) {
            case ".doc":
            case ".docx":
                strings[0] = "iconfont icon-DOC";
                strings[1] = "#1296db";
                break;
            case ".pdf":
                strings[0] = "iconfont icon-format-pdf";
                strings[1] = "#981605";
                break;
            case ".xls":
            case ".xlsx":
                strings[0] = "iconfont icon-PC-Excel";
                strings[1] = "#3fab46";
                break;
            case ".txt":
                strings[0] = "iconfont icon-wendang";
                strings[1] = "black";
            case ".png":
            case ".jpg":
            case ".jpeg":
                strings[0] = "iconfont icon-tupian";
                strings[1] = "";
        }
        return strings;
    }

    /**
     * 保存文件
     * @param bo
     * @return
     */
    @PostMapping("/file/saveFile")
    public R<Boolean> saveFile(@RequestBody ZWjglFlBo bo) {
        boolean b = iZWjglFlService.saveFile(bo);
        return R.ok(b);
    }

    /**
     * 获取文件内容
     * @param id
     * @return
     */
    @GetMapping("/file/getFileContent/{id}")
    public R<String> getFileContent(@PathVariable("id") String id) {
        String b = iZWjglFlService.getFileContent(id);
        return R.ok("获取完毕！", b);
    }

    /**
     * 获取文件详细信息
     *
     */
    @GetMapping(value = "/getFileStream/{id}")
    public byte[] getFileStream(@PathVariable String id) throws IOException {
        // 从文件或其他数据源获取PDF文件流
        // 1.通过id获取当前附件信息
        ZWjglFlVo zWjglFlVo = iZWjglFlService.queryById(id);
        // 2.获取附件路径
        String path = uploadPath + zWjglFlVo.getFilepath();
        // 3.获取文件
        File file = new File(path);
        FileInputStream inputStream = new FileInputStream(file);
        return IOUtils.toByteArray(inputStream);
    }

    /**
     * 校验文件名称
     * @param fileName
     * @param filetype
     * @return
     */
    @GetMapping("/verifyFileName/{fileName}/{filetype}")
    public R<Boolean> verifyFileName(@PathVariable("fileName") String fileName,
                                     @PathVariable("filetype") String filetype) {
        boolean b = iZWjglFlService.verifyFileName(fileName, filetype);
        return R.ok(b);
    }

    /**
     * 下载文件
     * @param id
     * @return
     */
    @GetMapping("/download/{id}")
    public byte[] downloadFile(@PathVariable String id) {
        FileInputStream inputStream = null;
        try {
            // 1.通过id获取当前附件信息
            ZWjglFlVo fujianVo = iZWjglFlService.queryById(id);
            // 2.获取附件路径
            String path = uploadPath + fujianVo.getFilepath();
            // 2.获取文件
            File file = new File(path);
            inputStream = new FileInputStream(file);
            return IOUtils.toByteArray(inputStream);
        } catch (MalformedURLException e) {
            throw new RuntimeException("Error: " + e.getMessage());
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    /**
     * 批量下载，下载压缩包
     */
    @GetMapping(value = "/batchDown", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    public void batchDown(@RequestParam("ids") String ids,  HttpServletResponse response) throws IOException {
        // 获取数据
        // 通过附件id，将附件查询出来
        List<ZWjglFlVo> zwjglFlList = iZWjglFlService.queryListByIds(ids);
        // 创建一个字节数组输出流，用于收集压缩后的数据
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ZipOutputStream zip = new ZipOutputStream(baos);
        try{
            for (int i = 0; i < zwjglFlList.size(); i++) {
                ZWjglFlVo zWjglFlVo = zwjglFlList.get(i);
                File file = new File(uploadPath + zWjglFlVo.getFilepath());
                if (file.exists()) {
                    FileInputStream fileInputStream = new FileInputStream(file);
                    byte[] data = new byte[fileInputStream.available()];
                    // 将数据读取到数组中
                    fileInputStream.read(data);
                    // 设置压缩包栏目
                    zip.putNextEntry(new ZipEntry(zWjglFlVo.getFilename() + zWjglFlVo.getFiletype()));
                    // 将数据写入压缩包中
                    zip.write(data);
                    zip.flush();
                    zip.closeEntry();
                    fileInputStream.close();
                }
            }
            org.apache.commons.io.IOUtils.closeQuietly(zip);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        byte[] zipData = baos.toByteArray();
        exportData(response, zipData);
    }
    /**
     * 生成zip文件
     */
    private void exportData(HttpServletResponse response, byte[] data) throws IOException
    {
        response.reset();
        response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
        response.setHeader("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With,X-App-Id, X-Token, Content-Disposition");
        response.setHeader("Content-Disposition", "attachment; filename=\"asp.zip\"");
        response.addHeader("Content-Length", "" + data.length);
        response.setContentType("application/octet-stream; charset=UTF-8");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        org.apache.commons.io.IOUtils.write(data, response.getOutputStream());
    }

    /**
     * 获取Base64文件流
     *
     */
    @GetMapping(value = "/getFileResource/{id}")
    public ResponseEntity<Resource> getFileResource(@PathVariable String id) throws IOException {
        // 1.通过id获取当前附件信息
        ZWjglFlVo fujianVo = iZWjglFlService.queryById(id);
        // 2.获取附件路径
        String path = uploadPath + fujianVo.getFilepath();
        Path filePath = Paths.get(path);
        // 3.获取文件
        Resource resource = new UrlResource(filePath.toUri());
        if (resource.exists() && resource.isReadable()) {
            return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
                .body(resource);
        } else {
            throw new RuntimeException("Could not read the file!");
        }
    }

    @GetMapping(value = "/getFileBae64/{id}")
    public String getFileBae64(@PathVariable String id) throws IOException {
        // 1.通过id获取当前附件信息
        ZWjglFlVo fujianVo = iZWjglFlService.queryById(id);
        // 2.获取附件路径
        String path = uploadPath + fujianVo.getFilepath();
        Path filePath = Paths.get(path);
        // 3.获取文件
        byte[] imageBytes = Files.readAllBytes(filePath);
        // 进行 Base64 编码
        String imageBase64 = Base64.getEncoder().encodeToString(imageBytes);
        return imageBase64;
    }

}
